package character.ai;

import board.BoardUtil;
import character.CharacterStatusType;
import character.MyCharacter;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;
import game.PlayerRelationship;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

/** If the AILogicControl represents the brain of the character, this control represents the senses and memory. */
public class AIGeneralControl extends AbstractControl {
    protected MyCharacter myCharacter;
    protected AILogicSettings aiLogicSettings;
    protected AILogicRoamControl roamControl = new AILogicRoamControl();
    protected AILogicCombatControl combatControl = new AILogicCombatControl();
    protected ThreatSystem threatSystem;
    protected Set<MyCharacter> visibleCharacters = new HashSet<MyCharacter>();
    
    @Deprecated
    protected AIGeneralControl() {}
    
    public AIGeneralControl(AILogicSettings aiLogicSettings) {
        this.aiLogicSettings = aiLogicSettings;
        threatSystem = new ThreatSystem(this);
    }

    @Override
    protected void controlUpdate(float tpf) {}
    
    public MyCharacter getClosestHostileCharacter() {
        int cardinalSpeed = myCharacter.getCharacterStats().getMoveSpeedWithModifier();
        int diagonalSpeed = myCharacter.getCharacterStats().getDiagonalMoveSpeedWithModifier();
        MyCharacter closest = null;
        for(MyCharacter character : getVisibleCharacters()) {
            if(character.getCharacterStatus().getCharacterStatusType() != CharacterStatusType.DEAD &&
                    myCharacter.getPlayer().getRelationship(character.getPlayer()) == PlayerRelationship.HOSTILE &&
                    (closest == null || 
                    BoardUtil.costBetween(myCharacter.getBoardLocation(), character.getBoardLocation(), cardinalSpeed, diagonalSpeed) <
                    BoardUtil.costBetween(myCharacter.getBoardLocation(), closest.getBoardLocation(), cardinalSpeed, diagonalSpeed))) {
                closest = character;
            }
        }
        return closest;
    }

    public Collection<MyCharacter> getVisibleCharacters() {
	return visibleCharacters;
    }
    public void addVisibleCharacter(MyCharacter character) {
	visibleCharacters.add(character);
    }
    public void addVisibleCharacters(Collection<MyCharacter> characters) {
	for(MyCharacter character : characters)
	    addVisibleCharacter(character);
    }
    public void removeVisibleCharacter(MyCharacter character) {
	visibleCharacters.remove(character);
    }
    public void removeVisibleCharacters(Collection<MyCharacter> characters) {
	for(MyCharacter character : characters)
	    removeVisibleCharacter(character);
    }

    public MyCharacter getMyCharacter() {
        return myCharacter;
    }

    public AILogicSettings getAILogicSettings() {
        return aiLogicSettings;
    }

    public AILogicRoamControl getAILogicRoamControl() {
        return roamControl;
    }
    
    public AILogicCombatControl getAILogicCombatControl() {
        return combatControl;
    }

    public ThreatSystem getThreatSystem() {
        return threatSystem;
    }

    @Override
    protected void controlRender(RenderManager rm, ViewPort vp) {}

    @Override
    public AIGeneralControl cloneForSpatial(Spatial spatial) {
	AIGeneralControl clone = new AIGeneralControl();
        spatial.addControl(clone);
	clone.visibleCharacters = new HashSet<MyCharacter>(visibleCharacters);
	return clone;
    }

    @Override
    public void setSpatial(Spatial spatial) {
        super.setSpatial(spatial);
        if(spatial != null) {
            myCharacter = (MyCharacter)spatial;
        }
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final AIGeneralControl other = (AIGeneralControl) obj;
        if (this.myCharacter != other.myCharacter && (this.myCharacter == null || !this.myCharacter.equals(other.myCharacter))) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 37 * hash + (this.myCharacter != null ? this.myCharacter.hashCode() : 0);
        return hash;
    }
}
